package com.durian.base.update.proxy.impl

import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import com.durian.BaseApp
import com.durian.base.update.XUpdate
import com.durian.base.update.entity.DownloadEntity
import com.durian.base.update.entity.VersionEntity
import com.durian.base.update.entity.XUpdateCheckErrorCode
import com.durian.base.update.entity.XUpdateException
import com.durian.base.update.proxy.*
import com.durian.base.utils.CoroutineKt
import com.durian.base.utils.GsonUtils
import com.durian.base.utils.NetUtils
import kotlinx.coroutines.*

class XUpdateRequestObserver(var lifecycle: Lifecycle? = null, var request: IUpdateRequest?) : LifecycleEventObserver {

    init {
        lifecycle?.addObserver(this)
    }

    override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
        if (event == Lifecycle.Event.ON_DESTROY) {
            XUpdate.getLog().i("移除XUpdateRequestObserver！")
            request?.destroy()
            lifecycle?.removeObserver(this)
            lifecycle = null
            request = null
        }
    }

}

open class XUpdateRequest : IUpdateRequest {

    private var _httpRequest: IHttpRequest? = null
    private var _updateChecker: IUpdateChecker? = null
    private var _updateListener: IUpdateListener? = null
    private var _updateConfig: IUpdateConfig? = null
    private var _updateDownloader: IUpdateDownloader? = null
    private var _updateInstaller: IUpdateInstaller? = null
    private var _requestJob: Job? = null

    override fun update(fragment: Fragment): IUpdateRequest {
        if (XUpdate.isDownloading()) {
            getUpdateListener()?.isDownloading()
            XUpdate.getLog().e("update()---正在下载中...")
            return this
        }
        XUpdate.init(fragment.context)
        XUpdateRequestObserver(fragment.lifecycle, this)
        _requestJob = CoroutineKt.Scope.launch(Dispatchers.IO) {
            try {
                doCheckUpdateBefore()
                if (doCheckNetwork()) {
                    doCheckUpdate()
                }
            }catch (e:Exception){
                doCheckUpdateError(XUpdateException(e, XUpdateCheckErrorCode.Unknown))
            }
        }
        return this
    }

    override fun update(activity: AppCompatActivity): IUpdateRequest {
        if (XUpdate.isDownloading()) {
            getUpdateListener()?.isDownloading()
            XUpdate.getLog().e("update()---正在下载中...")
            return this
        }
        XUpdate.init(activity)
        XUpdateRequestObserver(activity.lifecycle, this)
        _requestJob = CoroutineKt.Scope.launch(Dispatchers.IO) {
            try {
                doCheckUpdateBefore()
                if (doCheckNetwork()) {
                    doCheckUpdate()
                }
            }catch (e:Exception){
                doCheckUpdateError(XUpdateException(e, XUpdateCheckErrorCode.Unknown))
            }
        }
        return this
    }

    override fun setHttpRequest(httpRequest: IHttpRequest): IUpdateRequest {
        if (_httpRequest == null) {
            _httpRequest = httpRequest
        }
        return this
    }

    override fun getHttpRequest(): IHttpRequest? {
        return if (_httpRequest != null) {
            _httpRequest
        } else {
            XUpdate.getHttpRequest()
        }
    }

    override fun setUpdateChecker(updateChecker: IUpdateChecker): IUpdateRequest {
        if (_updateChecker == null) {
            _updateChecker = updateChecker
        }
        return this
    }

    override fun getUpdateChecker(): IUpdateChecker? {
        return if (_updateChecker != null) {
            _updateChecker
        } else {
            XUpdate.getUpdateChecker()
        }
    }

    override fun setUpdateListener(updateListener: IUpdateListener): IUpdateRequest {
        if (_updateListener == null) {
            _updateListener = updateListener
        }
        return this
    }

    override fun getUpdateListener(): IUpdateListener? {
        return if (_updateListener != null) {
            _updateListener
        } else {
            XUpdate.getUpdateListener()
        }
    }

    override fun setUpdateConfig(updateConfig: IUpdateConfig): IUpdateRequest {
        if (_updateConfig == null) {
            _updateConfig = updateConfig
        }
        return this
    }

    override fun getUpdateConfig(): IUpdateConfig? {
        return if (_updateConfig != null) {
            _updateConfig
        } else {
            XUpdate.getUpdateConfig()
        }
    }

    override fun setUpdateDownloader(updateDownloader: IUpdateDownloader): IUpdateRequest {
        if (_updateDownloader == null) {
            _updateDownloader = updateDownloader
        }
        return this
    }

    override fun getUpdateDownloader(): IUpdateDownloader? {
        return if (_updateDownloader != null) {
            _updateDownloader
        } else {
            XUpdate.getUpdateDownloader()
        }
    }

    override fun setUpdateInstaller(updateInstaller: IUpdateInstaller): IUpdateRequest {
        if (_updateInstaller == null) {
            _updateInstaller = updateInstaller
        }
        return this
    }

    override fun getUpdateInstaller(): IUpdateInstaller? {
        return if (_updateInstaller != null) {
            _updateInstaller
        } else {
            XUpdate.getUpdateInstaller()
        }
    }

    override fun getUpdateVersionController(): IUpdateVersionController {
        return this
    }

    override fun getUpdateInstallController(): IUpdateInstallController {
        return this
    }

    private fun cancelJob(){
        try {
            if (_requestJob != null) {
                _requestJob?.cancel()
            }
            _requestJob = null
        }catch (e : Exception){
            e.printStackTrace()
        }
    }

    override fun cancelUpdate() {
        cancelJob()
        XUpdate.setDownloading(false)
        XUpdate.getLog().i("cancelUpdate()---取消下载...")
    }

    override fun cancelInstall() {
        cancelJob()
        XUpdate.setDownloading(false)
        XUpdate.getLog().i("cancelInstall()---取消安装...")
    }

    override fun download(versionEntity: VersionEntity) {
        XUpdate.getLog().i("download()---开始下载...")
        startDownload(versionEntity, this)
    }

    override fun install(downloadEntity: DownloadEntity) {
        val updateInstaller = getUpdateInstaller()?:return
        updateInstaller.startInstall(downloadEntity)
        XUpdate.getLog().i("install()---开始安装...")
    }

    override fun startDownload(versionEntity: VersionEntity, updateRequest: IUpdateRequest) {
        val downloader = getUpdateDownloader() ?: return
        downloader.startDownload(versionEntity, this)
    }

    override fun destroy() {
        _httpRequest = null
        _updateChecker = null
        _updateListener = null
        _updateConfig = null
        cancelJob()
        XUpdate.getLog().i("XUpdateRequest.destroy()！")
    }

    private fun doCheckNetwork(): Boolean {
        var result = true
        if (!NetUtils.isNetConnected()) {
            doCheckUpdateError(XUpdateException(null, XUpdateCheckErrorCode.NoNetwork))
            result = false
            XUpdate.getLog().i("doCheckNetwork()---网络断开！")
        }else{
            XUpdate.getLog().i("doCheckNetwork()---网络连接！")
        }
        return result
    }

    private suspend fun doCheckUpdate() {
        try {
            val httpRequest = getHttpRequest() ?: return
            val updateChecker = getUpdateChecker() ?: return
            val updateListener = getUpdateListener() ?: return
            val updateConfig = getUpdateConfig() ?: return
            XUpdate.getLog().i("sendRequest()---开始请求版本数据！")
            val versionEntity = httpRequest.sendRequest()
            if (versionEntity == null){
                XUpdate.getLog().i("sendRequest()---版本数据请求失败，null")
                doCheckUpdateAfter()
                return
            }else{
                XUpdate.getLog().i("sendRequest()---版本数据请求成功，${GsonUtils.toJson(versionEntity)}")
            }
            if (updateConfig.showNotification() && updateConfig.setNotificationSmallIconRes() > 0){
                XUpdate.setSmallIcon(updateConfig.setNotificationSmallIconRes())
                XUpdate.getLog().i("setSmallIcon()---设置通知图标")
            }
            if (updateChecker.doCheckVersionEntity(versionEntity)) {
                XUpdate.getLog().i("doCheckVersionEntity()---发现新版本")
                withContext(Dispatchers.Main) {
                    updateListener.findNewVersion(this@XUpdateRequest, versionEntity)
                }
            } else {
                XUpdate.getLog().i("doCheckVersionEntity()---未检测到新版本")
                withContext(Dispatchers.Main) {
                    updateListener.noNewVersion()
                }
            }
            doCheckUpdateAfter()
        } catch (e: Exception) {
            doCheckUpdateError(XUpdateException(e, XUpdateCheckErrorCode.Unknown))
        }
    }

    private suspend fun doCheckUpdateBefore() {
        withContext(Dispatchers.Main) {
            val updateListener = getUpdateListener() ?: return@withContext
            updateListener.doCheckUpdateBefore()
            XUpdate.getLog().i("doCheckUpdateBefore()---开始检查新版本！")
        }
    }

    private suspend fun doCheckUpdateAfter() {
        withContext(Dispatchers.Main) {
            val updateListener = getUpdateListener() ?: return@withContext
            updateListener.doCheckUpdateAfter()
            XUpdate.getLog().i("doCheckUpdateAfter()---结束检查新版本！")
        }
    }

    private fun doCheckUpdateError(exception: XUpdateException) {
        val updateListener = getUpdateListener() ?: return
        BaseApp.handler().post {
            updateListener.doCheckUpdateException(exception)
            XUpdate.getLog().e("doCheckUpdateError()---${exception}！")
        }
    }

}